/*
    文件内容: 封装Epoll相关操作类
    文件名: Epoll.cpp
    作者: 中国好青年(码农论坛)
    时间: 2024/9/6

*/
#include "Epoll.h"

/* 
    函数名: Epoll()
    返回值: 无
    参  数: 无
    函数作用: 构造函数,创建epoll实例,为epollfd_赋值
*/
Epoll::Epoll()
{
    int tmpfd = epoll_create(1);
    if(tmpfd == -1)
    {
        printf("epoll_create error() exit\n");
        exit(-1);
    }
    epollfd_ = tmpfd;
}

/* 
    函数名: ~Epoll()
    返回值: 无
    参  数: 无
    函数作用: 析构函数,关闭epoll监听实例
*/
Epoll::~Epoll()
{
    close(epollfd_);
}

/*
    函数名: Epoll::loop(int timeout)
    返回值: 返回发生的事件数组
    参  数: int timeout, 超时事件, -1是不设置
    函数作用: 监听epoll_wait返回上来的事件
*/
std::vector<Channel*> Epoll::loop(int timeout)
{   
    std::vector<Channel*> tmpChannels;
    bzero(events_, sizeof(events_));
    int infds = epoll_wait(epollfd_, events_, MAX_EVENTS, timeout);
    if(infds < 0)
    {
        printf("epoll_wait error exit\n");
        exit(-1);
    }

    if(infds == 0)
    {   
        return tmpChannels;
    }
    
    for(int i = 0; i < infds; i++){
        Channel *ch = (Channel *)events_[i].data.ptr;
        ch -> setRevents(events_[i].events);
        tmpChannels.push_back(ch);
    }
    
    return tmpChannels;
}

/* 
    函数名: void updateChannel(Channel* ch)
    返回值: 无
    参  数: Channel成员,详见Channel.h
    函数作用: 对Channel中的fd在epoll树: [添加事件] [更改事件]
*/
void Epoll::updateChannel(Channel* ch)
{
    int ret = 0;
    struct epoll_event ev;

    ev.data.ptr = ch;
    ev.events  = ch -> events();
    
    if(ch -> inepoll())
    {
        ret = epoll_ctl(epollfd_, EPOLL_CTL_MOD, ch -> fd(), &ev);
    }
    else
    {
        ret = epoll_ctl(epollfd_, EPOLL_CTL_ADD, ch -> fd(), &ev);
        ch -> enableInepoll();
    }
    
    if(ret < 0)
	{
        printf("epoll_ctl error exit %s\n",ch->inepoll() ? "EPOLL_CTL_MOD" : "EPOLL_CTL_ADD");
        exit(-1);
    }
}

void Epoll::removeChannel(Channel* ch)
{   
    int ret = 0;

    if(ch -> inepoll())
    {
        ret = epoll_ctl(epollfd_, EPOLL_CTL_DEL, ch -> fd(), 0);
    }

    if(ret < 0)
    {
        printf("epoll_ctl EPOLL_CTL_DEL error\n");
    }
}